package org.example;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.compress.utils.IOUtils;

import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;

public class Main {

    public static JFrame frame = new JFrame("tar.gz打包");
    public static JTextField text = new JTextField(20);
    public static String selectFold = null;

    public static JTextArea area = new JTextArea(10, 1);

    public static void main(String[] args) {

        // Setting the width and height of frame
        frame.setSize(500, 800);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        /* 创建面板，这个类似于 HTML 的 div 标签
         * 我们可以创建多个面板并在 JFrame 中指定位置
         * 面板中我们可以添加文本字段，按钮及其他组件。
         */
        JPanel panel = new JPanel();
        // 添加面板
        frame.add(panel);
        /*
         * 调用用户定义的方法并添加组件到面板
         */
        placeComponents(panel);

        // 设置界面可见
        frame.setVisible(true);
    }

    private static void placeComponents(JPanel panel) {

        /* 布局部分我们这边不多做介绍
         * 这边设置布局为 null
         */
        panel.setLayout(null);

        // 创建 JLabel
        JButton button = new JButton("选择");
        /* 这个方法定义了组件的位置。
         * setBounds(x, y, width, height)
         * x 和 y 指定左上角的新位置，由 width 和 height 指定新的大小。
         */
        button.setBounds(10, 20, 60, 25);
        panel.add(button);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser folderChooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
                folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                folderChooser.showOpenDialog(null);
                selectFold = folderChooser.getSelectedFile() + "";
                text.setText(selectFold);
            }
        });

        /*
         * 创建文本域用于用户输入
         */
        text.setBounds(80, 20, 185, 25);
        panel.add(text);

        JButton button1 = new JButton("批量打包");
        button1.setBounds(270, 20, 90, 25);

        JButton button2 = new JButton("单个打包");//把一个目录下的文件一起打包到一个tar.gz
        button2.setBounds(370, 20, 90, 25);

        JButton button3 = new JButton("获取MD5");
        button3.setBounds(370, 50, 90, 25);
        button1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (selectFold == null) {
                    JOptionPane.showMessageDialog(frame, "请先选择文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //开始遍历目录下的文件
                File file = new File(selectFold);
                if (!file.isDirectory()) {
                    JOptionPane.showMessageDialog(frame, "请先选择文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                area.setText("");
                File[] files = file.listFiles();
                if (files != null) {
                    int i=0;
                    for (File f : files) {
                        if (f.isDirectory()) {
                            //跳过文件夹
                            continue;
                        }
                        String name = f.getName();
                        //文件夹名字
                        String foldName = name.substring(0, name.lastIndexOf("."));
                        File fold = new File(selectFold + File.separator + foldName);
                        if (!fold.exists()) {
                            fold.mkdir();
                            printLog("\n创建文件夹:" + fold.getName());
                        }
                        try {
                            //避免有中文名字的，文件的名字統一改成soft.exe
                            copyFile(f, fold.getAbsolutePath() + File.separator + "soft" + name.substring(name.lastIndexOf(".")));
                            printLog("\n复制文件到文件夹:");
                            //创建install.bat文件
                            creatBat(fold.getAbsolutePath(),name);

                            //创建压缩文件
                            String tarName = f.getParent() + File.separator + foldName + ".tar.gz";
                            tarCreate(fold.getAbsolutePath(), tarName);
                            //更改文件名字带MD5值
                            File tarFile = new File(tarName);
                            String MD5 = getFileMD5(tarFile);
                            File newTarFile = new File(f.getParent() + File.separator + foldName + "-" + MD5 + ".tar.gz");
                            tarFile.renameTo(newTarFile);

                            printLog("\n压缩完成");


                        } catch (IOException ex) {
                            throw new RuntimeException(ex);
                        }
                        i++;
                    }
                    printLog("\n执行结束，打包"+i+"个文件");
                }

            }
        });
        button2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //把目录下文件都打到一个tar.gz
                if (selectFold == null) {
                    JOptionPane.showMessageDialog(frame, "请先选择文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //开始遍历目录下的文件
                File file = new File(selectFold);
                if (!file.isDirectory()) {
                    JOptionPane.showMessageDialog(frame, "请先选择文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                File[] files = file.listFiles();
                if(files==null || files.length==0){
                    JOptionPane.showMessageDialog(frame, "文件夹下没有内容！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                File firstFile = files[0];
                if(firstFile.isDirectory()){
                    JOptionPane.showMessageDialog(frame, "目录下不要放文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }

                String name = firstFile.getName();
                try {
                    //创建bat文件
//                    creatBat(selectFold,name);

                    String foldName = name.substring(0,name.lastIndexOf("."));
                    File fold = new File(selectFold + File.separator + foldName);
                    if(!fold.exists()){
                        fold.mkdir();
                        printLog("创建文件夹："+foldName);
                    }
                    //创建tar.gz
                    String tarName = name + ".tar.gz";
                    String tarPath = fold.getAbsolutePath() + File.separator + tarName;
                    tarCreate(selectFold,tarPath);

                    File tarFile = new File(tarPath);
                    String MD5 = getFileMD5(tarFile);
                    File newTarFile = new File(fold.getAbsolutePath() + File.separator + MD5 + ".tar.gz");
                    tarFile.renameTo(newTarFile);
                    printLog("压缩完成");
                } catch (IOException ex) {
                    printLog("压缩出现异常"+ex.getMessage());
                    throw new RuntimeException(ex);
                }
            }
        });
        /**
         * 获取打好的包的MD5
         */
        button3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (selectFold == null) {
                    JOptionPane.showMessageDialog(frame, "请先选择文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //开始遍历目录下的文件
                File file = new File(selectFold);
                if (!file.isDirectory()) {
                    JOptionPane.showMessageDialog(frame, "请先选择文件夹！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                File[] files = file.listFiles();
                if(files==null || files.length==0){
                    JOptionPane.showMessageDialog(frame, "文件夹下没有内容！", "警告", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                for(File f:files){
                    String MD5 = getFileMD5(f);
                    File newTarFile = new File(selectFold + File.separator + f.getName().substring(0,f.getName().lastIndexOf(".tar.gz")) + "-" + MD5 + ".tar.gz");
                    f.renameTo(newTarFile);
                    printLog("获取"+f.getName()+"MD5完成\n");
                }
            }
        });
        panel.add(button1);
        panel.add(button2);
        panel.add(button3);

        area.setBounds(0, 0, 450, 650);
        area.setEditable(false);
        area.setLineWrap(true);
        JScrollPane scrollPane = new JScrollPane(area);
        scrollPane.setBounds(10, 80, 450, 650);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); // 设置垂直滚动条始终显示
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); // 设置水平滚动条按需显示
        panel.add(scrollPane);
    }


    public static void copyFile(File file, String destinationPath) throws IOException {
        FileInputStream inputStream = new FileInputStream(file);
        FileOutputStream outputStream = new FileOutputStream(destinationPath);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, length);
        }
        inputStream.close();
        outputStream.close();
    }


    /**
     * 压缩文件（tar.gz）
     *
     * @param srcFilePath 源文件
     * @param zipFilePath 压缩文件（*.tar.gz）
     */

    public static void tarCreate(String srcFilePath, String zipFilePath) throws IOException{
        try (TarArchiveOutputStream tos =
                     new TarArchiveOutputStream(
                             new GzipCompressorOutputStream(
                                     Files.newOutputStream(Paths.get(zipFilePath))))) {
            File file = new File(srcFilePath);
            File[] files = file.listFiles();
            assert files != null;
            for (File srcFile : files) {
                if (srcFile.isFile()) {
                    TarArchiveEntry entry = new TarArchiveEntry(srcFile.getName());
                    entry.setSize(srcFile.length());
                    tos.putArchiveEntry(entry);
                    IOUtils.copy(Files.newInputStream(srcFile.toPath()), tos);
                    tos.closeArchiveEntry();
                }
            }
            tos.finish();
        }
    }

    private static void printLog(String str){
        area.append(str);
        area.paintImmediately(area.getBounds());
    }

    /**
     *
     * @param foldPath  所在文件夹目录
     * @param name  要执行的文件名称
     * @throws IOException
     */
    private static void creatBat(String foldPath,String name) throws IOException {
        File bat = new File(foldPath + File.separator + "install.bat");
        if (!bat.exists()) {
            bat.createNewFile();
        }
        //写bat文件
        String str = "@echo off\n" +
                "cd /d \"%~dp0\"\n" +
                "start \"\" /wait "+
                "soft" + name.substring(name.lastIndexOf("."));
        FileWriter writer = new FileWriter(bat);
        writer.write(str);
        writer.flush();
        writer.close();
        printLog("\n写入bat文件结束");
    }

    /**
     * 获取文件MD5
     * @param file
     * @return
     */
    public static String getFileMD5(File file) {
        try {
            MessageDigest md5Digest = MessageDigest.getInstance("MD5");
            FileInputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[8192];
            int length;
            while ((length = fis.read(buffer)) != -1) {
                md5Digest.update(buffer, 0, length);
            }
            fis.close();
            byte[] md5Bytes = md5Digest.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : md5Bytes) {
                sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}